package com.cabal.notice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cabal.auth.dao.CabalAuthMapper;
import com.cabal.auth.dto.CraftItemDTO;
import com.cabal.auth.dto.CraftItemNoticeResponseDTO;
import com.cabal.auth.dto.PickUpItemNoticeDTO;
import com.cabal.auth.entity.CabalCharacter;
import com.cabal.auth.vo.CabalAuthVo;
import com.cabal.common.constants.SystemConstants;
import com.cabal.common.util.CabalGatewayMD5Util;
import com.cabal.common.util.DateApiUtil;
import com.cabal.common.util.SnowflakeIdUtil;
import com.cabal.config.DynamicDataSourceContextHolder;
import com.cabal.killed.service.impl.KilledServiceImpl;
import com.cabal.mall.dao.CabalCraftItemConfigMapper;
import com.cabal.mall.dao.CabalCraftItemResultRecordMapper;
import com.cabal.mall.dao.CabalPickUpItemConfigMapper;
import com.cabal.mall.entity.CabalCraftItemConfig;
import com.cabal.mall.entity.CabalCraftItemResultRecord;
import com.cabal.mall.entity.CabalPickUpItemConfig;
import com.cabal.notice.service.CabalNoticeService;
import com.cabal.socket.KilledWebSocketServer;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.nio.charset.Charset;
import java.util.*;

@Slf4j
@Service
public class CabalNoticeServiceImpl implements CabalNoticeService {

    private static String LOGIN_NOTICE_CONTENT = "$14#[%s][%s]$34#破空降临$37#%s %s";

    private static String LOGIN_NOTICE_KEY = "LOGIN_NOTICE_KEY_";

    private static String PICK_UP_ITEM_NOTICE_CONTENT = "$48#【恭喜】$37#[%s]$34#在副本中喜获 %s";

    private static String CRAFT_ITEM_SUCCESS_NOTICE_CONTENT = "$48#【热烈祝贺】$37#[%s]$34#被麒麟祥瑞守护成功制造 $7#%s";

    private static String CRAFT_ITEM_FAIL_NOTICE_CONTENT = "$34#【温馨提示】[%s]已累计制造%s次，当前连续制造失败%s次";

    @Resource
    private CabalAuthMapper cabalAuthMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private CabalPickUpItemConfigMapper cabalPickUpItemConfigMapper;

    @Value("${md5.secret_key}")
    private String secretKey;

    @Resource
    private CabalCraftItemResultRecordMapper cabalCraftItemResultRecordMapper;

    @Resource
    private CabalCraftItemConfigMapper cabalCraftItemConfigMapper;

    @Override
    public void loginNoticeJob() {
        // 1、查询数据库中角色表在线所有角色名称 所在线 职业
        List<CabalCharacter> cabalCharacterList = cabalAuthMapper.selectOnlineCharacterList();
        if(CollectionUtils.isEmpty(cabalCharacterList)) {
            log.info("没有在线玩家...");
            return;
        }

        String todayDate = DateApiUtil.format(new Date(), DateApiUtil.NORM_DATE_PATTERN);
        // 如果redis中的日期不等于今天则去掉
        Set<String> allKeys = stringRedisTemplate.keys(LOGIN_NOTICE_KEY + "*");
        for(Object key : allKeys) {
            String keyValue = stringRedisTemplate.opsForValue().get(key);
            if(keyValue.equals(todayDate)) {
                continue;
            }
            log.info("执行删除Key操作>>>>{}-{}", key, keyValue);
            stringRedisTemplate.delete(String.valueOf(key));
        }

        for(CabalCharacter cabalCharacter : cabalCharacterList) {
            Integer charId = cabalCharacter.getCharacterIdx();

            Integer userNum = charId / 8;
            CabalAuthVo cabalAuthVo = cabalAuthMapper.getCabalAuthVoByUserNum(userNum);
            if(cabalAuthVo.getVipLevel() == null || cabalAuthVo.getVipLevel() < 2) {
                continue;
            }

            String redisKey = LOGIN_NOTICE_KEY + charId;
            String exitChar = stringRedisTemplate.opsForValue().get(redisKey);
            if(StringUtils.isNotBlank(exitChar)) {
                continue;
            }

            String charName = getCharsetName(cabalCharacter.getName());
            Integer channelIdx = cabalCharacter.getChannelIdx();
            Integer worldIdx = cabalCharacter.getWorldIdx();
            Integer zy = cabalCharacter.getProfession();
            String mapMessage = StringUtils.isBlank(KilledServiceImpl.KILLED_MAP_MAP.get(worldIdx)) ?"异次元中心":KilledServiceImpl.KILLED_MAP_MAP.get(worldIdx);

            try {
                String sendMessage = String.format(LOGIN_NOTICE_CONTENT, KilledServiceImpl.PROFESSION_MAP.get(
                        zy),
                        charName,
                        KilledServiceImpl.KILLED_CHANNEL_MAP.get(channelIdx),
                        mapMessage);

                String base64Message = Base64.getEncoder().encodeToString(sendMessage.getBytes("GBK"));
                String encryptMessage = CabalGatewayMD5Util.md5(base64Message, secretKey, false);
                sendMessage = "GG|".concat(encryptMessage).concat("|").concat(base64Message);
                KilledWebSocketServer.sendMessageAll(sendMessage);
            } catch (Exception e) {
                log.error("消息发送失败>>>>", e);
            }

            stringRedisTemplate.opsForValue().set(redisKey, todayDate);

        }
    }

    @Override
    public String pickUpItemNotice(PickUpItemNoticeDTO pickUpItemNoticeDTO) {
        QueryWrapper<CabalPickUpItemConfig> queryWrapper = new QueryWrapper<CabalPickUpItemConfig>();
        queryWrapper.lambda().eq(CabalPickUpItemConfig::getItemId, Integer.parseInt(pickUpItemNoticeDTO.getItemId()));
        queryWrapper.lambda().eq(CabalPickUpItemConfig::getItemOption, Integer.parseInt(pickUpItemNoticeDTO.getItemOption()));
        DynamicDataSourceContextHolder.setContextKey(SystemConstants.DS_KEY_CABALMALL);
        int count = cabalPickUpItemConfigMapper.selectCount(queryWrapper);
        if(count < 1) {
            return "SUCCESS";
        }

        CabalPickUpItemConfig cabalPickUpItemConfig = cabalPickUpItemConfigMapper.selectOne(queryWrapper);
        DynamicDataSourceContextHolder.removeContextKey();
        String itemName = cabalPickUpItemConfig.getItemName();

        CabalAuthVo cabalAuthVo = cabalAuthMapper.getCabalAuthVoByAccount(pickUpItemNoticeDTO.getAccount());
        int iUserNum = cabalAuthVo.getUserNum();
        int startCharacterId = iUserNum * 8;
        int endCharacterId = startCharacterId + 5;

        CabalCharacter pickUpCabalCharacter = cabalAuthMapper.getCabalCharacterByCharacterId(startCharacterId, endCharacterId);
        try {
            String charName = getCharsetName(pickUpCabalCharacter.getName());

            String sendMessage = String.format(PICK_UP_ITEM_NOTICE_CONTENT, charName, itemName);
            log.info("发送消息打印>>>>" + sendMessage);
            String base64Message = Base64.getEncoder().encodeToString(sendMessage.getBytes("GBK"));
            String encryptMessage = CabalGatewayMD5Util.md5(base64Message, secretKey, false);
            sendMessage = "GG|".concat(encryptMessage).concat("|").concat(base64Message);
            KilledWebSocketServer.sendMessageAll(sendMessage);
        } catch (Exception e) {
            log.error("拾取公告消息发送失败>>>>", e);
        }
        return "SUCCESS";
    }

    @Override
    public CraftItemNoticeResponseDTO craftItemNotice(CraftItemDTO craftItemDTO) {
        CraftItemNoticeResponseDTO craftItemNoticeResponseDTO = new CraftItemNoticeResponseDTO();
        Integer craftState = Integer.parseInt(craftItemDTO.getCraftState());
        String account = craftItemDTO.getAccount();
        Integer craftId = Integer.parseInt(craftItemDTO.getCraftId());
        String itemName = "";

        DynamicDataSourceContextHolder.removeContextKey();
        CabalAuthVo cabalAuthVo = cabalAuthMapper.getCabalAuthVoByAccount(account);
        int iUserNum = cabalAuthVo.getUserNum();
        int startCharacterId = iUserNum * 8;
        int endCharacterId = startCharacterId + 5;

        CabalCharacter craftItemCabalCharacter = cabalAuthMapper.getCabalCharacterByCharacterId(startCharacterId, endCharacterId);
        Integer characterId = craftItemCabalCharacter.getCharacterIdx();
        String characterName = getCharsetName(craftItemCabalCharacter.getName());
        Integer userNum = cabalAuthVo.getUserNum();

        // 首先查询该角色+craftId在数据库中是否存在制造记录，如果没有则新增
        QueryWrapper<CabalCraftItemResultRecord> queryWrapper = new QueryWrapper<CabalCraftItemResultRecord>();
        queryWrapper.lambda().eq(CabalCraftItemResultRecord::getCharacterId, characterId);
        queryWrapper.lambda().eq(CabalCraftItemResultRecord::getCraftId, craftId);
        DynamicDataSourceContextHolder.setContextKey(SystemConstants.DS_KEY_CABALMALL);
        int count = cabalCraftItemResultRecordMapper.selectCount(queryWrapper);
        if(count < 1) {

            // 新增第一次制造记录
            CabalCraftItemResultRecord cabalCraftItemResultRecord = new CabalCraftItemResultRecord();
            cabalCraftItemResultRecord.setId(SnowflakeIdUtil.getInstance().nextId());
            cabalCraftItemResultRecord.setCraftId(craftId);
            cabalCraftItemResultRecord.setItemName(itemName);
            cabalCraftItemResultRecord.setCharacterId(characterId);
            if(craftState == 1) {
                cabalCraftItemResultRecord.setTotalCount(0);
                cabalCraftItemResultRecord.setCurrentConsecutiveFailCount(0);
                cabalCraftItemResultRecord.setCurrentFailRewardCount(0);
                cabalCraftItemResultRecord.setFailTotalCount(0);
                cabalCraftItemResultRecord.setSuccessCount(0);
                cabalCraftItemResultRecord.setMaxConsecutiveFailCount(0);
            } else {
                cabalCraftItemResultRecord.setTotalCount(0);
                cabalCraftItemResultRecord.setCurrentConsecutiveFailCount(0);
                cabalCraftItemResultRecord.setCurrentFailRewardCount(0);
                cabalCraftItemResultRecord.setFailTotalCount(0);
                cabalCraftItemResultRecord.setSuccessCount(0);
                cabalCraftItemResultRecord.setMaxConsecutiveFailCount(0);
            }

            cabalCraftItemResultRecordMapper.insert(cabalCraftItemResultRecord);
            /*craftItemNoticeResponseDTO.setCode("200");
            BeanUtils.copyProperties(cabalCraftItemResultRecord, craftItemNoticeResponseDTO);
            return craftItemNoticeResponseDTO;*/
        }

        // 根据craftId查询配置信息
        QueryWrapper<CabalCraftItemConfig> queryConfigWrapper = new QueryWrapper<CabalCraftItemConfig>();
        queryConfigWrapper.lambda().eq(CabalCraftItemConfig::getCraftId, craftId);
        queryConfigWrapper.lambda().eq(CabalCraftItemConfig::getCraftNum, 999);
        CabalCraftItemConfig cabalCraftItemConfig = cabalCraftItemConfigMapper.selectOne(queryConfigWrapper);
        if(cabalCraftItemConfig == null) {
            craftItemNoticeResponseDTO.setCode("500");
            return craftItemNoticeResponseDTO;
        }
        itemName = cabalCraftItemConfig.getItemName();

        CabalCraftItemResultRecord cabalCraftItemResultRecord = cabalCraftItemResultRecordMapper.selectOne(queryWrapper);
        CabalCraftItemResultRecord updateCabalCraftItemResultRecord;
        // 制造成功处理逻辑
        if(craftState == 1) {
            handleCraftSuccess(cabalCraftItemResultRecord, characterName, itemName);
        } else { // 制造失败处理逻辑
            updateCabalCraftItemResultRecord = handleCraftFail(cabalCraftItemResultRecord, userNum);
            String failRemindContent = String.format(CRAFT_ITEM_FAIL_NOTICE_CONTENT, itemName, updateCabalCraftItemResultRecord.getTotalCount(), updateCabalCraftItemResultRecord.getCurrentConsecutiveFailCount());
            craftItemNoticeResponseDTO.setFailRemindContent(failRemindContent);
        }

        craftItemNoticeResponseDTO.setCode("200");
        return craftItemNoticeResponseDTO;
    }

    private CabalCraftItemResultRecord handleCraftSuccess(CabalCraftItemResultRecord cabalCraftItemResultRecord, String characterName, String itemName) {
        CabalCraftItemResultRecord updateCabalCraftItemResultRecord = new CabalCraftItemResultRecord();
        updateCabalCraftItemResultRecord.setId(cabalCraftItemResultRecord.getId());
        // 1、制造成功更新数据库记录
        updateCabalCraftItemResultRecord.setTotalCount(cabalCraftItemResultRecord.getTotalCount() + 1);
        updateCabalCraftItemResultRecord.setSuccessCount(cabalCraftItemResultRecord.getSuccessCount() + 1);

        // 清零
        updateCabalCraftItemResultRecord.setCurrentConsecutiveFailCount(0);
        cabalCraftItemResultRecordMapper.updateById(updateCabalCraftItemResultRecord);

        // 2、制造成功公告
        try {
            String sendMessage = String.format(CRAFT_ITEM_SUCCESS_NOTICE_CONTENT, characterName, itemName);
            log.info("制造公告成功消息打印>>>>" + sendMessage);
            String base64Message = Base64.getEncoder().encodeToString(sendMessage.getBytes("GBK"));
            String encryptMessage = CabalGatewayMD5Util.md5(base64Message, secretKey, false);
            sendMessage = "GG|".concat(encryptMessage).concat("|").concat(base64Message);
            KilledWebSocketServer.sendMessageAll(sendMessage);
        } catch (Exception e) {
            log.error("制造公告成功消息发送失败>>>>", e);
        }

        return updateCabalCraftItemResultRecord;
    }

    private CabalCraftItemResultRecord handleCraftFail(CabalCraftItemResultRecord cabalCraftItemResultRecord, Integer userNum) {
        CabalCraftItemResultRecord updateCabalCraftItemResultRecord = new CabalCraftItemResultRecord();
        updateCabalCraftItemResultRecord.setId(cabalCraftItemResultRecord.getId());
        updateCabalCraftItemResultRecord.setTotalCount(cabalCraftItemResultRecord.getTotalCount() + 1);
        updateCabalCraftItemResultRecord.setFailTotalCount(cabalCraftItemResultRecord.getFailTotalCount() + 1);
        updateCabalCraftItemResultRecord.setCurrentConsecutiveFailCount(cabalCraftItemResultRecord.getCurrentConsecutiveFailCount() + 1);

        Integer currentConsecutiveFailCount = updateCabalCraftItemResultRecord.getCurrentConsecutiveFailCount();
        Integer maxConsecutiveFailCount = cabalCraftItemResultRecord.getMaxConsecutiveFailCount();
        if(currentConsecutiveFailCount > maxConsecutiveFailCount) {
            updateCabalCraftItemResultRecord.setMaxConsecutiveFailCount(currentConsecutiveFailCount);
        }

        // 当前连续失败次数currentConsecutiveFailCount是否等于制造配置的阈值，如果等于则发送奖励物品
        // 这里查询cabal_craft_item_config表，根据craft_id + currentConsecutiveFailCount
        QueryWrapper<CabalCraftItemConfig> queryWrapper = new QueryWrapper<CabalCraftItemConfig>();
        queryWrapper.lambda().eq(CabalCraftItemConfig::getCraftId, cabalCraftItemResultRecord.getCraftId());
        queryWrapper.lambda().eq(CabalCraftItemConfig::getCraftNum, currentConsecutiveFailCount);
        CabalCraftItemConfig cabalCraftItemConfig = cabalCraftItemConfigMapper.selectOne(queryWrapper);
        if(cabalCraftItemConfig == null) {
            cabalCraftItemResultRecordMapper.updateById(updateCabalCraftItemResultRecord);
            return updateCabalCraftItemResultRecord;
        }

        // 发送奖励物品
        Integer itemIdx = cabalCraftItemConfig.getItemId();
        Long itemOpt = cabalCraftItemConfig.getItemOption();
        Integer durationIdx = cabalCraftItemConfig.getDurationIdx();
        Map<String, Object> sendItemParams = new HashMap<>();
        sendItemParams.put("itemIdx", itemIdx);
        sendItemParams.put("itemOpt", itemOpt);
        sendItemParams.put("durationIdx", durationIdx);
        sendItemParams.put("userNum", userNum);
        DynamicDataSourceContextHolder.setContextKey(SystemConstants.DS_KEY_ACCOUNT);
        cabalAuthMapper.execSendItemByItemId(sendItemParams);

        updateCabalCraftItemResultRecord.setCurrentFailRewardCount(currentConsecutiveFailCount);
        DynamicDataSourceContextHolder.setContextKey(SystemConstants.DS_KEY_CABALMALL);
        cabalCraftItemResultRecordMapper.updateById(updateCabalCraftItemResultRecord);
        DynamicDataSourceContextHolder.removeContextKey();
        return updateCabalCraftItemResultRecord;
    }


    private String getCharsetName(String dbName) {
        Charset latin1Charset = Charset.forName("ISO-8859-1");
        Charset gbkCharset = Charset.forName("GBK");

        byte[] latin1Bytes = dbName.getBytes(latin1Charset);
        String decodedText = new String(latin1Bytes, gbkCharset);
        return decodedText;
    }
}
